#include <stdio.h>
#include <stdlib.h>
#include "List.h"

/***************************************************************************************************************/
/*********************************************    LIST_UTEST    *************************************************/
/***************************************************************************************************************/
#define IS_SUCCESS(X) !X?"SUCCESS":"FAILURE"   /*  Macro to print on regression tests       */
/*******************    Forward Declerations    ******************/
int ListRegression_Utest();
int ListPush_Utest();
int ListPop_Utest();
int ListFindIf_Utest();
int ListMultipile_Utest();
/*****************************************************************/

/****   IsMatch function for test   ****/
int IsIntMatch(void* _data, void* _param)
{
 return *((int*)_data) == *((int*)_param);
}
/***************************************/

/**     struct Person & Match func    **/
typedef struct Person_t
{
    int age;
    int id;
}Person;

int IsPersonMatch(void* _data, void* _param)
{
 return ((Person*)_data)->age == *((int*)_param);
}
/***************************************/

int main()
{
    ListRegression_Utest();

    return 0;
}

int ListRegression_Utest()
{
    printf("ListPush_Utest: %s\n\n", IS_SUCCESS(ListPush_Utest()));
    printf("ListFindIf_Utest: %s\n\n", IS_SUCCESS(ListFindIf_Utest()));
    printf("ListPop_Utest: %s\n\n", IS_SUCCESS(ListPop_Utest()));
    printf("ListMultipile_Utest: %s\n", IS_SUCCESS(ListMultipile_Utest()));

    return 0;
}


int ListPush_Utest()
{
    List*   list = ListNew();
    int     numArr[] = {1,2,3,4,5,6,7};
    int     numArr2[] = {8,9,10};
    int*    data1;
    int*    data2;
    int     i;
    int     numOfE;

    if(!ListIsEmpty(list) )
    {  return 1;  }

    if(ListCount(list) )
    {  return 1;  }

    printf("The arguments pushed to list: ");
    for(i = (sizeof(numArr)/sizeof(int)); i > 0; --i)
    {
        ListPushH(list, numArr + i-1);
        printf("%d ",*(numArr + i - 1));
    }
    if(sizeof(numArr)/sizeof(int) != ListCount(list))
    {  return 1;  }
    data1 = ListHead(list);
    if(*data1 != numArr[0])
    {  return 1;  }
    data2 = ListTail(list);
    if(*data2 != numArr[sizeof(numArr)/sizeof(int) -1])
    {  return 1;  }
    printf("\nNow pushing to tail: ");
    for(i = 0; i < (sizeof(numArr2)/sizeof(int)); ++i)
    {
        ListPushT(list, numArr2 + i);
        printf("%d ",*(numArr2 + i));
    }
    printf("\nThe args in list: %d\n", ListCount(list));
    numOfE = ListCount(list);
    printf("Now pop from head and prints the head after the popping\n");
    for(i = 0; i < numOfE; ++i)
    {
        data1 = ListHead(list);
        if(*data1 != i+1)
        {  return 1;  }
        printf("The element is: %d\n", *data1);
        ListPopH(list);
    }

    return 0;
}


int ListPop_Utest()
{
    List*   list = ListNew();
    int     numArr[] = {1,2,3,4,5,6,7};
    int     numArr2[] = {8,9,10};
    int*    data1   ;
    int*    data2   ;
    int     i       ;
    int     numOfE  ;

    printf("Check in start IsEmpty: %d\n", ListIsEmpty(list));
    printf("The args in list (at start): %d\n", ListCount(list));

    printf("The arguments pushed to list: ");
    for(i = (sizeof(numArr)/sizeof(int)); i > 0; --i)
    {
        ListPushH(list, numArr + i-1);
        printf("%d ",*(numArr + i - 1));
    }
    printf("\nThe args pushed to list are: %d 'in list: %d\n",sizeof(numArr)/sizeof(int), ListCount(list));
    data1 = ListHead(list);
    data2 = ListTail(list);
    printf("The last one is: %d\n", *data2);
    printf("The first one is: %d\n", *data1);
    printf("Now pushing to tail: ");

    for(i = 0; i < (sizeof(numArr2)/sizeof(int)); ++i)
    {
        ListPushT(list, numArr2 + i);
        printf("%d ",*(numArr2 + i));
    }

    printf("\nThe args in list: %d\n", ListCount(list));
    numOfE = ListCount(list);
    printf("Now pop from tail and prints the tail after popping\n");

    for(i = 0; i < numOfE; ++i)
    {
        data1 = ListTail(list);
        printf("The element is: %d\n", *data1);
        ListPopT(list);
    }

    return 0;
}

int ListFindIf_Utest()
{
    List* list = ListNew();
    Person pArr[5];
    Person* pp = pArr;
    int i;
    int age = 3;

    for(i = 0; pp < pArr + sizeof(pArr)/sizeof(Person); ++pp, ++i)
    {
        pp->age = i;
        pp->id = i*i;
    }
    printf("Insert array of Perons to list\n");
    ListPushTM(list, sizeof(Person), sizeof(pArr)/sizeof(Person), pArr);
    printf("The list count is: %d\n", ListCount(list));
    pp = ListFindIf(list, IsPersonMatch, &age);
    printf("The searched age was: %d, the person found age: %d, id: %d\n", age, pp->age, pp->id);
    if(age != pp->age)
    {  return 1;  }

    return 0;
}

int ListMultipile_Utest()
{
    List* list = ListNew();
    Person pArr[5];
    Person* pp = pArr;
    int i;
    int numOfeE;
    int popSizeH = 1;
    int popSizeT = 3;

    printf("The ages inserted all of them in order head and by order from tail\n");
    for(i = 0; pp < pArr + sizeof(pArr)/sizeof(Person); ++pp, ++i)
    {
        pp->age = i;
        printf("%d ", i);
        pp->id = i*i;
    }
    ListPushTM(list, sizeof(Person), sizeof(pArr)/sizeof(Person), pArr);
    ListPushHM(list, sizeof(Person), sizeof(pArr)/sizeof(Person), pArr);


    printf("\nThe list count is: %d\n", ListCount(list));
    if(ListCount(list) != 2*sizeof(pArr)/sizeof(Person) )
    {  return 1;  }
    ListPopHM(list, popSizeH);
    printf("The list count after removed %d items from head is: %d\n", popSizeH,ListCount(list));
    if(ListCount(list) != 2*sizeof(pArr)/sizeof(Person) - popSizeH )
    {  return 1;  }
    ListPopTM(list, popSizeT);
    printf("The list count after removed %d items from tail is: %d\n", popSizeT,ListCount(list));
    if(ListCount(list) != 2*sizeof(pArr)/sizeof(Person) - popSizeH -popSizeT)
    {  return 1;  }
    printf("The ages after %d popped from head, and %d from tail\n",popSizeH, popSizeT);
    numOfeE = ListCount(list);
    for(i = 0; i < numOfeE ; ++i)
    {
        pp = ListHead(list);
        printf("%d ", pp->age);
        ListPopH(list);
    }
    puts("\n");
    ListDel(list);

    return 0;
}


